﻿using ServerCommon.Config;
using ServerCommon.Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ServerCommon.Architecture
{
    public enum ServerStatusType
    {
        Unknow,
        Init,
        Run,
        Pause,
        Stop,
        Release
    }

    public enum ProgramServerType
    {
        Unknown,
        Channel,
        Platform,
        Database,
        Login,
        Game,
        Gateway,
        World,
        GM,
        Robot,
    }

    public class ProgramServer
    {
        private ServerStatusType _serverStatus;
        public ServerStatusType ServerStatus => _serverStatus;

        private Stopwatch _tickWatch;
        public Stopwatch TickWatch => _tickWatch;

        private bool _exit;

        private long _frameCur;
        private long _frameEnd;
        private long _frameCost;

        public int OvertimeMax { get; set; }
        public int OvertimeMin { get; set; }
        public int Sleeptime { get; set; }

        public static ProgramServer? Instance => _instance;
        protected static ProgramServer? _instance;

        public ProgramServerType ServerType => _serverType;
        private ProgramServerType _serverType;

        public long ServerId => _serverId;  //单个游戏进程的id，多个进程组成一个完整的游戏世界
        private long _serverId;

        public int GroupId => _groupId;     //一组进程组成的完整的游戏世界的游戏服id，比如一服，二服
        private int _groupId;

        public int ZoneId => _zoneId;       //大区id，比如一大区，二大区，一个大区有多个groupid
        private int _zoneId;

        public string AppName => _name;
        private string _name;

        public ProgramServer()
        {
            _serverStatus = ServerStatusType.Unknow;
            _serverType = ProgramServerType.Unknown;
            _serverId = 0;
            _tickWatch = new Stopwatch();
            _exit = false;
            _frameCur = 0;
            _frameEnd = 0;
            _frameCost = 0;
            OvertimeMax = 30;
            OvertimeMin = 10;
            Sleeptime = 1;

            ExitSignal.Instance.Exit += onExit;
        }

        public virtual int Init(ProgramServerType serverType, string appName, string configPath, long serverId = 0)
        {
            _serverType = serverType;
            _name = appName;

            string NetConfigFile = configPath + "/NetConfig.json";
            string ServerConfigFile = configPath + "/ServerConfig.json";
            ConfigManager.Instance.InitNetConfig(NetConfigFile);
            ConfigManager.Instance.InitServerConfig(ServerConfigFile);

            _zoneId = ConfigManager.Instance.ServerConfig.Value<int>("ZoneId");
            _groupId = ConfigManager.Instance.ServerConfig.Value<int>("GroupId");
            if(serverId == 0)
            {
                var Config = ConfigManager.Instance.ServerConfig[appName];
                long Id = Config.Value<long>("Id");
                _serverId = Id;
            }
            else
            {
                _serverId = serverId;
            }

            ProtocolList.Register();

            _tickWatch.Start();

            Console.WriteLine("{0}, ZoneId - {1}, GroupId - {2}, ServerId - {3} Init!", _name, _zoneId, _groupId, _serverId);
            return 0;
        }

        public virtual void Run()
        {
            Console.WriteLine("{0}, ZoneId - {1}, GroupId - {2}, ServerId - {3} Run!", _name, _zoneId, _groupId, _serverId);
        }

        public virtual void Stop()
        {
            _exit = true;
            Console.WriteLine("{0}, ZoneId - {1}, GroupId - {2}, ServerId - {3} Stop!", _name, _zoneId, _groupId, _serverId);
        }

        public virtual void Release()
        {
            _tickWatch.Stop();
            Console.WriteLine("{0}, ZoneId - {1}, GroupId - {2}, ServerId - {3} Release!", _name, _zoneId, _groupId, _serverId);
        }

        public void UpdateStatus(ServerStatusType status)
        {
            _serverStatus = status;
            Console.WriteLine("{0}, ZoneId - {1}, GroupId - {2}, ServerId - {3}, UpdateStatus - {4}!", _name, _zoneId, _groupId, _serverId, _serverStatus);
        }

        protected void waitFor(Func<long, bool> mainFunc, Func<long, bool> overtimeFunc)
        {
            if(mainFunc == null || overtimeFunc == null)
            {
                return;
            }

            while(!_exit)
            {
                _frameCur = _tickWatch.ElapsedMilliseconds;

                //执行主循环
                if(!mainFunc(_frameCur))
                {
                    break;
                }

                _frameEnd = _tickWatch.ElapsedMilliseconds;
                _frameCost = _frameEnd - _frameCur;

                if(_frameCost > OvertimeMax)
                {
                    //超时了执行超时函数
                    overtimeFunc(_frameCost);
                }

                //时间充裕，sleep一定的时间（毫秒）
                if(OvertimeMin > _frameCost)
                {
                    Thread.Sleep((int)(OvertimeMin - _frameCost));
                }
            }
        }

        private void onExit(object? sender, EventArgs ev)
        {
            Stop();
        }
    }


    public class ProgramServer<T> : ProgramServer where T : ProgramServer, new()
    {
        public new static T? Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new T();
                }
                return _instance as T;
            }
        }
    }
}
